package org.flexspeedup.blog.admin.views
{
import flash.events.Event;
import flash.events.MouseEvent;

import mx.events.FlexEvent;
import mx.validators.StringValidator;
import mx.validators.Validator;

import org.flexspeedup.blog.admin.events.ChangePostCategoryEvent;
import org.flexspeedup.blog.admin.types.Sections;
import org.flexspeedup.blog.events.NavigateToEvent;
import org.flexspeedup.blog.events.NotifyChangeEvent;
import org.flexspeedup.blog.events.ShowPopUpEvent;
import org.flexspeedup.blog.models.PopUpModel;
import org.flexspeedup.model.IListModel;
import org.flexspeedup.view.TLFTextEditor;

import spark.components.Button;
import spark.components.DropDownList;
import spark.components.TextInput;
import spark.components.supportClasses.SkinnableComponent;
import spark.events.IndexChangeEvent;
import spark.events.TextOperationEvent;

[SkinState("normal")]
[SkinState("pendingChanges")]

[Event(name="done", type="flash.events.Event")]
[Event(name="save", type="flash.events.Event")]
/**
 * Component logic for a post editor
 */
public class PostEditor extends SkinnableComponent
{

    //--------------------------------------------------------------------------
    //
    //  Class constants
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  POST_CHAR_LIMIT
    //----------------------------------
    /**
     * @priv
     */
    private static const POST_CHAR_LIMIT:int = 400;

    //----------------------------------
    //  STATIC_PAGE_CHAR_LIMIT
    //----------------------------------
    /**
     * @priv
     */
    private static const STATIC_PAGE_CHAR_LIMIT:int = 1200;

    //----------------------------------
    //  POST
    //----------------------------------
    /**
     * The editor type for posts
     */
    public static const POST:String = "post";

    //----------------------------------
    //  STATIC_PAGE
    //----------------------------------
    /**
     * The editor type for static pages
     */
    public static const STATIC_PAGE:String = "staticPage";

    //--------------------------------------------------------------------------
    //
    // Constructor
    //
    //--------------------------------------------------------------------------

    /**
     * Creates a new <code>PostEditor</code> instance.
     */
    public function PostEditor()
    {
        super();
        addEventListener(FlexEvent.REMOVE, removeHandler);
    }

    //--------------------------------------------------------------------------
    //
    //  Skin parts
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  titleInput
    //----------------------------------
    [SkinPart(required="true")]
    public var titleInput:TextInput;

    //----------------------------------
    //  editor
    //----------------------------------
    [SkinPart(required="true")]
    public var editor:TLFTextEditor;

    //----------------------------------
    //  saveButton
    //----------------------------------
    [SkinPart(required="true")]
    public var saveButton:Button;

    //----------------------------------
    //  cancelButton
    //----------------------------------
    [SkinPart(required="false")]
    public var cancelButton:Button;

    //----------------------------------
    //  doneButton
    //----------------------------------
    [SkinPart(required="false")]
    public var doneButton:Button;

    //----------------------------------
    //  categoryDropDown
    //----------------------------------
    [SkinPart(required="false")]
    public var categoryDropDown:DropDownList;

    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  validators
    //----------------------------------
    
    /**
     *  @private
     */
    
    private var _validators:Array;
    /**
     *  @private
     */
    private function get validators():Array
    {
        if (!_validators)
        {
            _validators = [];
            
            var titleValidator:Validator = new Validator();
            titleValidator.required = true;
            titleValidator.source = titleInput;
            titleValidator.property = "text";
            titleValidator.requiredFieldError = "this field is required";
            _validators.push(titleValidator);
            
            var bodyValidator:StringValidator = new StringValidator();
            bodyValidator.required = true;
            bodyValidator.maxLength = 
                editorType == POST ? POST_CHAR_LIMIT : STATIC_PAGE_CHAR_LIMIT;
            bodyValidator.source = editor.editor;
            bodyValidator.property = "text";
            bodyValidator.tooLongError = "your text is too long. please make it shorter";
            bodyValidator.requiredFieldError = "this field is required";
            _validators.push(bodyValidator);
            
            if (categoryDropDown)
            {
                var categoryValidator:Validator = new Validator();
                categoryValidator.required = true;
                categoryValidator.source = categoryDropDown;
                categoryValidator.property = "selectedItem";
                categoryValidator.requiredFieldError = "this field is required";
                _validators.push(categoryValidator);
            }
        }

        return _validators;
    }

    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    // editorType
    //----------------------------------
    /**
     * The editor type: post/static page.
     */
    public var editorType:String = POST;
   

    //----------------------------------
    // editorItem
    //----------------------------------
    [Bindable]
    /**
     * The item to be edited.
     */
    public var editorItem:Object;
   
    //----------------------------------
    //  categoryModel
    //----------------------------------
    /**
     *  @private
     */    
    private var _categoryModel:IListModel;
    
    [Bindable]
    /**
     * The model for the category drop down
     */
    public function get categoryModel():IListModel
    {
        return _categoryModel;
    }
    
    public function set categoryModel(value:IListModel):void
    {
        _categoryModel = value;
    }


    //----------------------------------
    //  hasPendingChanges
    //----------------------------------
    /**
     *  @private
     */    
    private var _hasPendingChanges:Boolean;
    [Bindable]
    /**
     * True if there is any un-saved change in the app
     */
    public function get hasPendingChanges():Boolean
    {
        return _hasPendingChanges;
    }
    
    public function set hasPendingChanges(value:Boolean):void
    {
        _hasPendingChanges = value;
        invalidateSkinState();
    }


    //--------------------------------------------------------------------------
    //
    //  Overridden Methods - SkinnableComponent
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     */
    override protected function partAdded(partName:String, instance:Object):void
    {
        super.partAdded(partName, instance);
        
        switch (instance)
        {
            case (titleInput):
            {
                titleInput.addEventListener(
                    TextOperationEvent.CHANGE,
                    titleInput_changeHandler
                );
                break;
            }
            
            case (editor):
            {
                editor.addEventListener(
                    TextOperationEvent.CHANGE, 
                    editor_changeHandler
                );
                editor.addEventListener(
                    TLFTextEditor.FORMAT_OR_LINK_CHANGE,
                    editor_formatOrLinkChangeHandler
                );
                break;
            }
            
            case (saveButton):
            {
                saveButton.addEventListener(
                    MouseEvent.CLICK,
                    saveButton_clickHandler
                );
                break;
            }
            
            case (cancelButton):
            {
                cancelButton.addEventListener(
                    MouseEvent.CLICK,
                    cancelButton_clickHandler
                );
                break;
            }
            
            case (doneButton):
            {
                doneButton.addEventListener(
                    MouseEvent.CLICK,
                    cancelButton_clickHandler
                );
                break;
            }
            
            case (categoryDropDown):
            {
                categoryDropDown.addEventListener(
                    IndexChangeEvent.CHANGE,
                    categoryDropDown_changeHandler
                );
                break;
            }
            
        }
    }

    /**
     *  @private
     */
    override protected function partRemoved(partName:String, instance:Object):void
    {
        switch (instance)
        {
            case (titleInput):
            {
                titleInput.removeEventListener(
                    TextOperationEvent.CHANGE,
                    titleInput_changeHandler
                );
                break;
            }
            
            case (editor):
            {
                editor.removeEventListener(
                    TextOperationEvent.CHANGE, 
                    editor_changeHandler
                );
                editor.removeEventListener(
                    TLFTextEditor.FORMAT_OR_LINK_CHANGE,
                    editor_formatOrLinkChangeHandler
                );            
                break;
            }
            case (saveButton):
            {
                saveButton.removeEventListener(
                    MouseEvent.CLICK,
                    saveButton_clickHandler
                );
                break;
            }
            
            case (cancelButton):
            {
                cancelButton.removeEventListener(
                    MouseEvent.CLICK,
                    cancelButton_clickHandler
                );
                break;
            }
            
            case (doneButton):
            {
                doneButton.removeEventListener(
                    MouseEvent.CLICK,
                    cancelButton_clickHandler
                );
                break;
            }
            
        }
    }

    /**
     *  @private
     */
    override protected function getCurrentSkinState():String
    {
        if (hasPendingChanges)
            return "pendingChanges";
        else
            return "normal";
    }

    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  notifyChange
    //----------------------------------
    /**
     * @private
     */
    private function notifyChange():void
    {
        dispatchEvent(new NotifyChangeEvent());    
    } 

    //----------------------------------
    //  validate
    //----------------------------------
    /**
     * @private
     */
    private function validate():Boolean
    {
        if (Validator.validateAll(validators).length > 0)
            return false; 
        return true;
    } 

    //----------------------------------
    //  save
    //----------------------------------
    /**
     * @private
     */
    private function save():void
    {
        dispatchEvent(new Event("save"));
    } 

    //----------------------------------
    //  validationError
    //----------------------------------
    /**
     * @private
     */
    private function validationError():void
    {
        var popUpModel:PopUpModel = new PopUpModel(
            "your form has errors",
            "you forgot to fill in something, please check"
        );
        dispatchEvent(new ShowPopUpEvent(popUpModel));
    }

    //----------------------------------
    //  cleanup
    //----------------------------------
    /**
     * @private
     */
    private function cleanup():void
    {
        titleInput.text = "";
        editor.editor.text = "";

        titleInput.errorString = "";
        editor.editor.errorString = "";
        
        if (categoryDropDown)
        {
            categoryDropDown.selectedItem = null;
            categoryDropDown.errorString = "";
        }
    } 

    //----------------------------------
    //  done
    //----------------------------------
    /**
     * @private
     */
    private function done():void
    {
        dispatchEvent(new Event("done"));    
    } 

    //--------------------------------------------------------------------------
    //
    //  Event Handlers
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  titleInput_changeHandler
    //----------------------------------
    /**
     * @private
     */
    private function titleInput_changeHandler(event:TextOperationEvent):void
    {
        notifyChange();
    }
    
    //----------------------------------
    //  editor_changeHandler
    //----------------------------------
    /**
     * @private
     */
    private function editor_changeHandler(event:TextOperationEvent):void
    {
        notifyChange();
    }

    //----------------------------------
    //  saveButton_clickHandler
    //----------------------------------
    /**
     * @private
     */
    private function saveButton_clickHandler(event:MouseEvent):void
    {
        if(validate())
            save();
        else
            validationError();
    }

    //----------------------------------
    //  cancelButton_clickHandler
    //----------------------------------
    /**
     * @private
     */
    private function cancelButton_clickHandler(event:MouseEvent):void
    {
        done();        
    }

    //----------------------------------
    //  doneButton_clickHandler
    //----------------------------------
    /**
     * @private
     */
    private function doneButton_clickHandler(event:MouseEvent):void
    {
        done();        
    }

    //----------------------------------
    //  categoryDropDown_changeHandler
    //----------------------------------
    /**
     * @private
     */
    private function categoryDropDown_changeHandler(event:IndexChangeEvent):void
    {
        notifyChange();
        dispatchEvent(new ChangePostCategoryEvent(categoryDropDown.selectedItem));
    }

    //----------------------------------
    //  editor_formatOrLinkChangeHandler
    //----------------------------------
    /**
     * @private
     */
    private function editor_formatOrLinkChangeHandler(event:Event):void
    {
        notifyChange();
    }

    //----------------------------------
    //  removeHandler
    //----------------------------------
    /**
     * @private
     */
    private function removeHandler(event:FlexEvent):void
    {
        cleanup();
    }
}
}